//
//  SLPagerHelper.m
//  SLPagerView
//
//  Created by l.t.zero on 2022/1/7.
//

#import "SLPagerHelper.h"
#import <objc/runtime.h>

void sl_dispatch_main_sync_safe(dispatch_block_t block){
    if ([NSThread isMainThread]) {
        block();
    } else {
        dispatch_sync(dispatch_get_main_queue(), block);
    }
}

NSArray *sl_array_map(NSArray *array, sl_map_block block ){
    if(!block) return @[];
    
    NSMutableArray *tmp = [NSMutableArray new];
    
    [array enumerateObjectsUsingBlock:^(id  _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
        id item = block(obj);
        if (item){
            [tmp addObject:item];
        }
    }];
    
    return tmp;
}
NSArray *sl_array_filter(NSArray *array, sl_filter_block block ){
    if(!block) return nil;
    
    NSMutableArray *tmp = [NSMutableArray new];
    
    [array enumerateObjectsUsingBlock:^(id  _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
        if (block(obj)){
            [tmp addObject:obj];
        }
    }];
    
    return tmp;
}

@implementation SLPagerObject

- (NSInteger)index{
    return self.indexPath?self.indexPath.row:-1;
}

- (BOOL)isEqual:(SLPagerObject *)object{
    if ([object class] == [self class]){
        return [self.item isEqual:[object item]]
        && [self.indexPath isEqual:[object indexPath]]
        && [self.view isEqual:object.view]
        && self.scrolling == object.scrolling;
    }
    return NO;
}

- (Class)classForCell{
    return [self.view class];
}

@end

SLPagerObject *pagerObjectFrom(id view, NSIndexPath *indexPath, id item){
    SLPagerObject *obj = [SLPagerObject new];
    obj.view = view;
    obj.indexPath = indexPath;
    obj.item = item;
    return obj;
}



void sl_pager_item_add_cell_for_class(id obj, sl_pager_add_block block){
    SEL sel = NSSelectorFromString(@"classForCell");

    if (![obj respondsToSelector:sel]){
        Class cls = [obj class];
        Method method = class_getInstanceMethod(cls, sel);
        const char *types = method_getTypeEncoding(method);
        if (class_addMethod(cls, sel, imp_implementationWithBlock(block), types)){
        }
    }
}

/**
 *@discussion 解决UICollectionView/UITableView reloadData时，会强制调用resignFirstResponder
 *@param view  查询保证第一响应者的parentView
 *@param block 保证第一响应者期间需要处理的代码块
 */
void sl_protectResignFirstResponderIn(UIView *view, dispatch_block_t block) {
    if (!view || !block) return;
    
    UIView* (^__block search_first_responder)(UIView *) =  ^UIView *(UIView * view){
        if (view.isFirstResponder) return view;
        
        for (UIView *subview in view.subviews) {
            UIView *first = nil;
            if ((first = search_first_responder(subview))) {
                return first;
            }
        }
        
        return nil;
    };
    
    ///递归遍历view的所有subviews，寻找第一响应者
    UIResponder *responder = search_first_responder(view);
    if (!responder) {
        block();
        return;
    }
   
    NSString *oldClass = NSStringFromClass([responder class]);
    NSString *newClass = [@"_protected_resign_xprade1_" stringByAppendingString:oldClass];
    Class cls = NSClassFromString(newClass);
    
    ///通过block来代替selector的执行
    void (^addMethod)(SEL sel, id block) = ^(SEL sel, id block) {
        Method classMethod = class_getInstanceMethod([responder class], sel);
        const char *classTypes = method_getTypeEncoding(classMethod);
        IMP imp = imp_implementationWithBlock(block);
        class_addMethod(cls, sel, imp, classTypes);
    };
    
    if (cls == NULL){
        cls = objc_allocateClassPair([responder class], newClass.UTF8String, 0);
        objc_registerClassPair(cls);
        
        ///添加resignFirstResponder
        addMethod(@selector(resignFirstResponder), ^BOOL (id self){
            return NO;
        });
        ///添加class 返回类型跟父类一致，保证调用无异常
        addMethod(@selector(class), ^Class (id self){
            return class_getSuperclass(object_getClass(self));
        });
    }
    
    ///将responder isa指向子类，进行resignFirstResponder拦截
    ///执行完代码块，恢复responder isa为原有类型
    Class old = responder.class;
    object_setClass(responder, cls);
    block();
    object_setClass(responder, old);
    
    ///注销新类
    //objc_disposeClassPair(cls);

}
